﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;

namespace ufs
{
    public class BalanceUploadMiddleware : IMiddleware
    {
        IHttpClientFactory _httpClientFactory;
        UFSConfig _config;
        IConfiguration _configuration;
        int downstreamIndex = 0;

        public BalanceUploadMiddleware(IHttpClientFactory httpClientFactory, IConfiguration configuration,
            IOptions<UFSConfig> options)
        {
            _httpClientFactory = httpClientFactory;
            _configuration = configuration;
            _config = options.Value;
        }

        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            UFSResult resultInfo = new UFSResult();
            var theConfig = _config;
            //项目文件夹
            string app = null;
            if (context.Request.Headers.TryGetValue("app", out StringValues appFolders))
            {
                app = appFolders.ToString();
            }
            else
            {
                app = "default";
            }

            if (app != "default")
            {
                var appConfig = _configuration.GetSection("ufs").GetSection(app).Get<UFSConfig>();
                if (appConfig != null)
                {
                    theConfig = appConfig;
                    if (theConfig.AllowExts == null) theConfig.AllowExts = _config.AllowExts;
                    if (theConfig.LimitSize == null) theConfig.LimitSize = _config.LimitSize;
                    if (theConfig.AccessToken == null) theConfig.AccessToken = _config.AccessToken;
                    if (theConfig.Downstreams == null) theConfig.Downstreams = _config.Downstreams;
                }
            }

            //accessToken验证
            context.Request.Headers.TryGetValue("accesstoken", out StringValues accessTokens);
            if (!theConfig.AccessToken.Equals(accessTokens.ToString()))
            {
                resultInfo.Msg = "invoid token";
                await context.Response.WriteAsync(resultInfo.ToString());
                return;
            }

            //大小验证
            if (context.Request.ContentLength != null && context.Request.ContentLength > theConfig.LimitSize)
            {
                resultInfo.Msg = "file is too large!";
                await context.Response.WriteAsync(resultInfo.ToString());
                return;
            }

            //后缀名验证
            string ext = null;
            if (context.Request.Headers.TryGetValue("ext", out StringValues fileExts))
            {
                ext = fileExts.ToString();
                if (!theConfig.AllowExts.Contains(ext))
                {
                    resultInfo.Msg = "invalid file ext";
                    await context.Response.WriteAsync(resultInfo.ToString());
                    return;
                }
            }
            else
            {
                resultInfo.Msg = "no file ext info";
                await context.Response.WriteAsync(resultInfo.ToString());
                return;
            }

            try
            {
                MemoryStream ms = new MemoryStream();

                int blockSize = 1024;
                var buffer = new byte[blockSize];
                int count = 0;
                while ((count = await context.Request.Body.ReadAsync(buffer, 0, blockSize)) > 0)
                {
                    await ms.WriteAsync(buffer, 0, count);
                }

                //验证最终大小
                if (ms.Length > theConfig.LimitSize)
                {
                    resultInfo.Msg = "file is too large!";
                    await context.Response.WriteAsync(resultInfo.ToString());
                    return;
                }

                ms.Position = 0;
                StreamContent content = new StreamContent(ms);

                content.Headers.Add("ext", ext);
                content.Headers.Add("app", app);
                var downstream = GetDownstream(theConfig.Downstreams);

                var httpClient = _httpClientFactory.CreateClient();
                httpClient.Timeout = TimeSpan.FromMinutes(10);
                var response = await httpClient.PostAsync(downstream + "/uploadfile", content);

                var nodeResult = await response.Content.ReadAsStringAsync();
                await context.Response.WriteAsync(nodeResult);
                return;
            }
            catch (Exception exp)
            {
                resultInfo.Msg = "【ufs】：" + exp.Message;
            }

            await context.Response.WriteAsync(resultInfo.ToString());
        }


        private string GetDownstream(List<string> list)
        {
            if (downstreamIndex >= list.Count)
            {
                downstreamIndex = 0;
            }

            return list[downstreamIndex++];
        }
    }
}